#pragma once

#include <stddef.h>
#include <stdint.h>

/**
 * @brief 哈希表节点，应该嵌入到实际的数据结构中
 */
struct HNode 
{
    HNode *next = NULL;     ///< 链表下一个节点指针
    uint64_t hcode = 0;     ///< 哈希值
};

/**
 * @brief 简单的固定大小哈希表
 */
struct HTab 
{
    HNode **tab = NULL;     ///< 槽位数组
    size_t mask = 0;        ///< 数组大小掩码，2^n - 1
    size_t size = 0;        ///< 键的数量
};

/**
 * @brief 真正的哈希表接口，使用两个哈希表实现渐进式rehash
 */
struct HMap 
{
    HTab newer;             ///< 新哈希表
    HTab older;             ///< 旧哈希表
    size_t migrate_pos = 0; ///< 迁移位置
};

/**
 * @brief 在哈希表中查找节点
 * @param hmap 哈希表指针
 * @param key 查找的键节点
 * @param eq 比较函数
 * @return 找到的节点指针，未找到返回NULL
 */
HNode *hm_lookup(HMap *hmap, HNode *key, bool (*eq)(HNode *, HNode *));

/**
 * @brief 在哈希表中按键查找节点
 * @param hmap 哈希表指针
 * @param key 键数据
 * @param len 键长度
 * @return 找到的节点指针，未找到返回NULL
 */
HNode *hm_lookup(HMap *hmap, const uint8_t *key, size_t len);

/**
 * @brief 向哈希表中插入节点
 * @param hmap 哈希表指针
 * @param node 要插入的节点
 */
void hm_insert(HMap *hmap, HNode *node);

/**
 * @brief 从哈希表中删除节点
 * @param hmap 哈希表
 * @param key 键
 * @param len 键长度
 * @return 删除的节点，如果不存在返回NULL
 */
HNode *hm_pop(HMap *hmap, const uint8_t *key, size_t len);

/**
 * @brief 清空哈希表
 * @param hmap 哈希表指针
 */
void hm_clear(HMap *hmap);

/**
 * @brief 获取哈希表大小
 * @param hmap 哈希表指针
 * @return 哈希表中的元素数量
 */
size_t hm_size(HMap *hmap);

/**
 * @brief 初始化哈希表
 * @param hmap 哈希表指针
 */
void hm_init(HMap *hmap);

/**
 * @brief 扫描哈希表中的节点
 * @param hmap 哈希表
 * @param from 起始位置指针
 * @return 下一个节点，如果没有更多节点返回NULL
 */
HNode *hm_scan(HMap *hmap, HNode **from);

/**
 * @brief 遍历哈希表中的所有节点
 * @param hmap 哈希表指针
 * @param f 回调函数，返回false时停止遍历
 * @param arg 传递给回调函数的参数
 */
void hm_foreach(HMap *hmap, bool (*f)(HNode *, void *), void *arg);

/**
 * @brief 从哈希表中删除节点
 * @param hmap 哈希表指针
 * @param key 要删除的键节点
 * @param eq 比较函数
 * @return 被删除的节点，如果不存在则返回NULL
 */
HNode *hm_delete(HMap *hmap, HNode *key, bool (*eq)(HNode *, HNode *)); 